package com.allwees.support.payment.paypal;

import com.paypal.api.payments.Payment;
import com.paypal.base.rest.APIContext;
import com.paypal.core.PayPalEnvironment;
import com.paypal.http.HttpResponse;
import com.paypal.http.exceptions.HttpException;
import com.paypal.orders.LinkDescription;
import com.paypal.orders.Order;
import com.paypal.orders.OrdersCaptureRequest;
import com.paypal.orders.OrdersCreateRequest;
import com.paypal.payments.CapturesRefundRequest;
import com.paypal.payments.Refund;
import com.allwees.bs.core.modelbase.constant.ResultEnum;
import com.allwees.bs.core.modelbase.exception.BusinessException;
import com.allwees.support.payment.model.PaymentInfo;
import com.allwees.support.payment.model.RefundInfo;
import com.allwees.support.payment.paypal.builder.OrderRequestBuilder;
import com.allwees.support.payment.paypal.builder.RefundRequestBuilder;
import com.allwees.support.payment.paypal.client.PayPalClient;
import com.allwees.support.payment.paypal.configuration.PaypalProperties;
import com.allwees.support.payment.paypal.util.PayPalUtil;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

@Slf4j
public class PaypalAccountStrategy {

    public static Map<String, String> create(PaymentInfo paymentInfo) {
        OrdersCreateRequest request = new OrdersCreateRequest();
        request.header("prefer", "return=representation");
        request.requestBody(OrderRequestBuilder.build(paymentInfo));

        HttpResponse<Order> response = null;
        try {
            response = PayPalClient.getInstance().execute(request);
        } catch (IOException e) {
            log.error(">>>>>>>>>> paypal", e);
            throw BusinessException.getInstance(ResultEnum.PAYMENT_PAYPAL_CREATE_ERROR);
        }
        if (response.statusCode() != 201) {
            log.error(">>>>>>>> paypal create not is approved:" + response.statusCode() + ",order uuid：" + paymentInfo.getOrderUuid());
            throw BusinessException.getInstance(ResultEnum.PAYMENT_PAYPAL_CREATE_ERROR);
        }
        return _createResult(response);
    }

    public static String capture(String orderUuid, String token) {
        OrdersCaptureRequest request = new OrdersCaptureRequest(token);
        request.requestBody(OrderRequestBuilder.buildEmpty());

        HttpResponse<Order> response = null;
        try {
            response = PayPalClient.getInstance().execute(request);
        } catch (HttpException ex) {
            if(ex.getMessage().contains("ORDER_ALREADY_CAPTURED")){
                return null;
            }
            log.error(">>>>>>>>>> paypal", ex);
            throw BusinessException.getInstance(ResultEnum.PAYMENT_PAYPAL_CREATE_ERROR);
        } catch (IOException e) {
            log.error(">>>>>>>>>> paypal", e);
            throw BusinessException.getInstance(ResultEnum.PAYMENT_PAYPAL_CREATE_ERROR);
        }
        if (response.statusCode() != 201) {
            log.error(">>>>>>>> paypal create not is approved:" + response.statusCode() + ",order uuid：" + orderUuid);
            throw BusinessException.getInstance(ResultEnum.PAYMENT_PAYPAL_CREATE_ERROR);
        }
        return response.result().purchaseUnits().get(0).payments().captures().get(0).id();
    }

    public static String refund(RefundInfo refundInfo) {
        CapturesRefundRequest request = RefundRequestBuilder.build(refundInfo);

        HttpResponse<Refund> response = null;
        try {
            response = PayPalClient.getInstance().execute(request);
        } catch (IOException e) {
            log.error(">>>>>>>>>> paypal", e);
            throw BusinessException.getInstance(ResultEnum.PAYMENT_PAYPAL_CREATE_ERROR);
        }
        if (response.statusCode() != 201) {
            log.error(">>>>>>>> paypal create not is approved:" + response.statusCode() + ",order item uuid：" + refundInfo.getOrderItemUuid());
            throw BusinessException.getInstance(ResultEnum.PAYMENT_PAYPAL_CREATE_ERROR);
        }
        return response.result().id();
    }

    public static Payment appCapture(String paymentId, String payerId, String mode){
        PayPalEnvironment environment = PaypalProperties.getEnvironment();
        APIContext apiContext = new APIContext(environment.clientId(), environment.clientSecret(), mode);

        // 生成paypal支付对象
        Payment payment = new Payment();

        try {
            payment = Payment.get(apiContext, paymentId);
        } catch (Exception e) {
            log.error(">>>>>>>>>> paypal execute error,paymentId:{},payId:{}", paymentId, payerId, e);
            throw BusinessException.getInstance(ResultEnum.PAYMENT_PAYPAL_CREATE_ERROR);
        }
        if (!PayPalUtil.isSuccess(payment.getState())) {
            log.error(">>>>>>>> paypal回调支付不是approved" + payment.getState() + "paymentId：" + paymentId);
            return null;
        }
        return payment;
    }

    private static Map<String, String> _createResult(HttpResponse<Order> response) {
        Map<String, String> map = new HashMap<>(2);
        map.put("id", response.result().id());

        LinkDescription link = response.result().links().stream().filter(l -> l.rel().equals("approve")).findFirst().get();
        map.put("approveUrl", link.href());

        return map;
    }
}
